home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 134_01.zip / CORODOC.NRO < prev    next >
Text File  |  1993-06-12  |  24KB  |  617 lines

  1. .pl 66
  2. .rm 65
  3. .m1 4
  4. .m2 2
  5. .m3 2
  6. .m4 4
  7. .he 'BDS C Coroutine Package''Introduction'
  8. .fo '28 May 1983'-#-'K. B. Kenny'
  9. .ls 1
  10. .ce 3
  11. Coroutine Package for BDS C
  12. by
  13. Kevin B. Kenny
  14. .sp 2
  15. .ul 1
  16. Acknowledgements.
  17. .sp
  18. .ti +5
  19. The BDS 'C' coroutine package is based on one developed at the University of
  20. Waterloo for the programming language 'B' by I. D. Allen.  The author
  21. is also indebted to Peter Fraser, who explained the Waterloo implementation
  22. and provided much good advice for the 'C' version.
  23. .sp 2
  24. .ul 1
  25. 1. Introduction: What are coroutines?
  26. .sp
  27. .ti +5
  28. Every programmer is familiar with the concept of subroutines; portions
  29. of a program that, in effect, provide extensions to the hardware and
  30. allow the programmer to think of complex tasks as sequences of simpler
  31. ones.  While this way of thinking about subroutines is enormously useful,
  32. another view is possible: a main program and its subroutines can be seen
  33. as a team of actors, each with its own job to do.  When the main program
  34. has a task that some subroutine performs, it asks that subroutine for service;
  35. when the subroutine finishes its job, it exits to the main program.
  36. .sp
  37. .ti +5
  38. When a very complex subroutine is written, it is difficult to see it as
  39. simply performing a service for the main program; it might be equally valid
  40. to say that when the subroutine exits to the main program, it is asking
  41. the main program to perform a service for it.  The main program does its
  42. duty, then returns to the subroutine for further orders.
  43. .sp
  44. .ti +5
  45. Consider, for instance, a program which has very complicated operations
  46. to perform on an input stream, eventually producing an output stream.
  47. If the input routine is very complicated, we are tempted to make it the
  48. "main program" and generate the output stream by calling an "output
  49. subroutine".  If, on the other hand, the output procedure is complex,
  50. we are tempted to make
  51. .ul 1
  52. it
  53. the "main program," retrieving its data from the "input subroutine."
  54. What do we do when they are both complicated procedures and neither one
  55. can conveniently be made into a subroutine?
  56. .sp
  57. .ti +5
  58. The solution to this problem is to use
  59. .ul 1
  60. coroutines.
  61. Coroutines are components of a program which are like subroutines in that
  62. they are called from outside (although the correct technical term is
  63. that they are
  64. .ul 1
  65. resumed).
  66. Unlike subroutines, however, neither one of them is the "main program."  
  67. Each can call on the other in as many places as necessary; when one needs
  68. a service (from its point of view) it resumes the other one.  Rather than
  69. entering it from the beginning, however, the machine picks up the
  70. resumed coroutine
  71. .ul 1
  72. exactly where it left off.
  73. The second coroutine then continues processing until, from
  74. .ul 1
  75. its
  76. point of view, it needs the services of the first.  It then resumes the
  77. first coroutine, which is entered where it left off processing.
  78. .sp
  79. .ti +5
  80. To each of the coroutines, then, the other appears as a subroutine.  The
  81. first resumes the second, and the second returns to the first.  This
  82. is the fundamental difference between subroutines and coroutines:  while
  83. a subroutine is always entered at the beginning, a coroutine is always
  84. entered at the point where it left off.
  85. .he 'BDS C Coroutine Package''Rationale'
  86. .sp 3
  87. .ul 1
  88. 2. Rationale: Why use coroutines?
  89. .sp
  90. .ti +5
  91. It is difficult to come up with a simple example of the use of coroutines,
  92. since they are most useful in interfacing two or more complicated tasks.
  93. Generally, if one of the tasks is fairly simple, it is easier to implement
  94. as a subroutine; making a coroutine of it seems contrived.
  95. .sp
  96. .ti +5
  97. The most common uses of coroutines in practice arise either in terms of
  98. multi-pass algorithms or in simulation.  Multi-pass algorithms can use
  99. coroutines to implement the passes, with each resuming the next when it
  100. has output to be processed by the next pass and resuming the prior pass when
  101. input is required.
  102. Simulations can use coroutines to act like independent processes; for instance,
  103. a simulation of a machine shop might use one coroutine to represent each
  104. machine and pass the simulated workpiece around by having these coroutines
  105. resume one another.
  106. .sp
  107. .ti +5
  108. The first of these, the multipass algorithm, is probably more familiar to
  109. C programmers, since Unix pipelines operate this way.  When the user enters
  110. a command like
  111. .sp
  112. .ti +10
  113. .bo
  114. foo | bar | zot
  115. .sp
  116. the system sets up three coroutines, corresponding to the commands "foo,"
  117. "bar," and "zot."
  118. It then enters the "zot" coroutine to begin the processing.
  119. .sp
  120. .ti +5
  121. Things proceed normally until the first time "zot" needs a character from the
  122. standard input stream.  When it does, it calls "getchar" as usual; "getchar"
  123. sees that "zot" has a predecessor in the pipeline.  Rather than reading the
  124. character from the terminal or some file, it resumes "bar" to get the
  125. character.
  126. .sp
  127. .ti +5
  128. Now "bar" starts running, and eventually needs an input character itself.  When
  129. it does, it calls "getchar," who sees that "bar" isn't the first command in the
  130. pipeline either.  As before, it resumes the preceding coroutine, "foo."
  131. "Foo" runs normally, and since it is the first coroutine in the pipe, its calls
  132. to "getchar" cause input from the standard input stream.
  133. .sp
  134. .ti +5
  135. Eventually, "foo" has some output to place on the output stream.  It calls
  136. "putchar," who sees that "foo" isn't the last command in the pipeline.  Instead
  137. of writing the character somewhere, "putchar" resumes the "bar" coroutine,
  138. passing the character to it.  Since "bar" left off processing in "getchar"
  139. where it resumed "foo", it is in just the right state to pick up the character
  140. and continue processing, exactly as if it had been the first command in
  141. the pipeline and got the character from the input stream.
  142. .sp
  143. .ti +5
  144. "Foo" and "bar" continue passing and receiving characters until "bar" has
  145. output to the output stream.  As with "foo", it calls "putchar," who sees
  146. that "bar" isn't the last command in the pipe, either.  It then resumes
  147. "zot", who has been waiting all this time for its first input character.
  148. "Zot" is, of course, still in "getchar;" he picks up the character which
  149. "bar" gave to "putchar" and continues processing.  Since "zot" is the
  150. last coroutine in the pipeline, its calls to "putchar" go on the standard
  151. output stream.
  152. .sp
  153. .ti +5
  154. The disc for the coroutine package contains a sample program organized as
  155. a Unix-style pipeline, in the file "retab.c".  "Retab" consists of the two
  156. programs "entab" and "detab" from
  157. .ul 1
  158. Software Tools,
  159. connected together in the sequence
  160. .sp
  161. .ti +10
  162. .bo
  163. detab | entab
  164. .sp
  165. so that the combination will convert the tabs in its input file to spaces,
  166. and then reconvert them to tabs, possibly at a different set of tab stops.
  167. .sp 3
  168. .he 'BDS C Coroutine Package''Functions Available'
  169. .ul 1
  170. 3. Functions Available in the Coroutine Package.
  171. .sp
  172. .ti +5
  173. The most basic functions available in the coroutine package are C_CREATE,
  174. which creates a coroutine; C_RESUME, which passes control to another coroutine,
  175. and C_DESTROY, which destroys a coroutine.  All of these primitives operate
  176. on a dynamically-allocated area of memory called the
  177. .ul 1
  178. "function control vector (FCV)."
  179. C_CREATE obtains an area of memory from free storage and initializes it as
  180. an FCV, C_RESUME accepts an FCV and transfers into the associated coroutine,
  181. and C_DESTROY accepts an FCV and recovers the space used.
  182. .sp
  183. .ti +5
  184. While these functions are sufficient to implement any application involving
  185. coroutines, the BDS C package supplies several additional primitives to make
  186. certain jobs somewhat easier.
  187. .sp
  188. .ti +5
  189. First, each coroutine has one word of user-specified information in its FCV.
  190. This word, which is set by C_CREATE, can be examined by C_GETINFO and
  191. modified by C_SETINFO.  Normally this word will be a pointer to a structure
  192. containing static storage for the coroutine to use.  For instance, if
  193. the coroutine is modelling a server in a queueing network, the area might
  194. contain head and tail pointers for the queue of transactions waiting for
  195. that server.
  196. .sp
  197. .ti +5
  198. The local static storage pointer in the FCV becomes particularly important
  199. if there are multiple copies of the same procedure.  For instance, in the
  200. Unix environment, the user might have typed
  201. .sp
  202. .ti +10
  203. .bo
  204. foo | lowercase | bar | lowercase
  205. .sp
  206. which runs the program "foo", converts the result to lower case, presents
  207. the lowercase material to "bar" as input, and lowercases the result.  Imagine
  208. the chaos that would result if both copies of "lowercase" used the same
  209. static and external storage areas!
  210. .sp
  211. .ti +5
  212. Another facility which the BDS 'C' package provides is the ability to
  213. create a hierarchy of coroutines in a "parent-child" relationship.  This
  214. is done by means of the primitives C_CALL and C_DETACH.
  215. C_CALL puts a pointer to the calling coroutine's FCV in the FCV of the
  216. called coroutine, indicating that the caller is the "parent" of the callee.
  217. It then resumes the callee normally.  If the callee does a C_DETACH, the
  218. effect is to resume the caller again.  In this way, the callee has no need
  219. to know which coroutine invoked it but can always return control to it.
  220. .sp
  221. .ti +5
  222. In addition, any coroutine which is invoked by the callee using C_RESUME
  223. inherits the parent linkage.  C_RESUME copies the pointer to the parent
  224. coroutine from the FCV of the origin to the destination FCV.  If the
  225. destination coroutine does a C_DETACH, the effect is to resume the
  226. original caller.
  227. .sp
  228. .ti +5
  229. The analogue to these three mechanisms is the CALL, GO TO, and RETURN
  230. functions of ordinary subroutines.  A subroutine invoked by GO TO inherits
  231. the caller of the one that did the GO TO.  Any RETURN goes back to the
  232. most recent CALL, even if it did not call the present subroutine directly.
  233. Similarly, a coroutine invoked by C_RESUME inherits the caller of the
  234. one that did the C_RESUME.  Any C_DETACH goes back to the most recent C_CALL,
  235. even if the C_CALL did not directly call the current coroutine.
  236. .sp
  237. .ti +5
  238. Finally, a number of functions are available to query and alter the state of
  239. a coroutine.  C_WMI returns a pointer to the FCV of the current coroutine.
  240. C_PASSER returns a pointer to the FCV of the coroutine that directly 
  241. transferred to this one (via C_CALL, C_RESUME, or C_DETACH); C_TYPE tells
  242. which of the three methods was used.  C_CALLER returns a pointer to the
  243. "caller" coroutine, i.e., the one to which a C_DETACH would transfer control.
  244. Lastly, C_CALLBY allows a coroutine to change its caller and DETACH elsewhere.
  245. While this function is needed in some advanced applications, its use is
  246. rather esoteric and it will not be discussed further.
  247. .sp 3
  248. .he 'BDS C Coroutine Package''Implementation'
  249. .ul 1
  250. 4. Implementation of Coroutines in 'C'.
  251. .sp
  252. .ti +5
  253. In order to discuss how coroutines are implemented in 'C', let us first examine
  254. what information must be preserved in order to be able to leave a 'C' procedure
  255. and return to it.
  256. Clearly, the most important item is the program counter (PC).  It is
  257. obviously impossible to return to a procedure if we don't know where it
  258. left off processing.
  259. The rest of the procedure's state is described by the contents of its
  260. variables.
  261. .sp
  262. .ti +5
  263. External variables present no problems; they are preserved across the calls
  264. and returns between procedures.  Auto variables, however, must have some
  265. other mechanism, since a procedure exit destroys them.  This requirement
  266. leads us to the definition:
  267. .sp
  268. .ul 2
  269. A BDS C coroutine is a set of procedures with their own stack, distinct
  270. from the stack of any other coroutine.
  271. .sp
  272. .ti +5
  273. Given a separate stack, we have a place to preserve the PC, and the program's
  274. registers (most notably BC, the current stack frame pointer).  We still need
  275. a place to store the stack pointer when the coroutine is not in execution.
  276. This area of memory is the 
  277. .ul 1
  278. function control vector (FCV).
  279. The FCV contains, in addition to the stack pointer, contains other information
  280. about the coroutine's state:
  281. .sp
  282. .in +4
  283. .ti -2
  284. - the passer, which is the coroutine that most recently transferred control
  285. to this one.
  286. .sp
  287. .ti -2
  288. - the type of control transfer (CALL, RESUME, or DETACH) that invoked the
  289. current coroutine most recently.
  290. .sp
  291. .ti -2
  292. - the caller, i.e., the coroutine to which DETACH will transfer control.
  293. .sp
  294. .ti -2
  295. - the size of the coroutine's stack.  This information is available for
  296. stack tracers and the like, which normally assume that the end of the
  297. 'C' stack is the same as the top of the TPA.
  298. .sp
  299. .ti -2
  300. - one word of user-specified information, normally a pointer to some private
  301. static storage.
  302. .sp
  303. .in -4
  304. .ti +5
  305. The address of the FCV is the coroutine's unique identification.  Any function
  306. that operates on a coroutine accepts the FCV as the indicator of which
  307. coroutine to use.
  308. The structure of an FCV is defined in the #include file "coro.h".
  309. .sp
  310. .ti -5
  311. Within a coroutine, function call and return operate just as they do
  312. within an ordinary C program using the main stack.  Just as function calls
  313. can overflow the main C stack, they can overflow the coroutine's stack.
  314. Non-local transfers (SETJMP/LONGJMP) work, but with the limitation that
  315. it is possible to LONGJMP only to a point which was set within the current
  316. coroutine.  An attempt to LONGJMP to another coroutine will appear to
  317. work, but in fact the stack pointer will have changed without storing
  318. it in the FCV.  On any subsequent attempt to transfer into either coroutine,
  319. the package will get confused and make a mess of things.
  320. .sp 3
  321. .he 'BDS C Coroutine Package''Creating a Coroutine'
  322. .ul 1
  323. 5. Creating a Coroutine
  324. .sp
  325. .ti +5
  326. A coroutine is created in BDS 'C' by a call of the following form:
  327. .sp
  328. .ti +10
  329. .bo
  330. fcv = c_create (function, stack [, userinfo] );
  331. .sp
  332. where "fcv" is the pointer to the new coroutine's FCV, "function" is the
  333. initial entry of the coroutine (its "main program", if you will),
  334. "stack" is the number of bytes of stack space required, and
  335. "userinfo" is the word to place in the user area of the FCV.
  336. .sp
  337. .ti +5
  338. C_Create takes the following actions to initialize the coroutine:
  339. .sp
  340. .in +4
  341. .ti -2
  342. - It gets space for the FCV and the stack from free memory.  The
  343. FCV and stack area are cleared to zero.
  344. .sp
  345. .ti -2
  346. - The stack size word in the FCV is initialized.  The stack pointer is set
  347. to point to the location two words before the end of the stack area.  These
  348. locations are the initial stack for the coroutine, and are initialized as
  349. follows:
  350. .sp
  351. .in +4
  352. .ti -2
  353. - Word SP+0 is set to the address of the initial entry.  This word will be
  354. loaded into the BC register when the coroutine is first entered via any of
  355. the transfer mechanisms.
  356. .sp
  357. .ti -2
  358. - Word SP+2 is set to the address of a "driver" procedure, CORSTART.  This
  359. is a short program, discussed below, which enters the coroutine at its
  360. initial entry point.  Any of the transfer mechanisms will get to CORSTART
  361. on initial entry by doing a RET instruction to this word in the stack.
  362. .sp
  363. .in -4
  364. .ti -2
  365. - The "caller" word in the FCV is initialized to designate the current
  366. coroutine, for want of a better choice.
  367. .sp
  368. .ti -2
  369. - The user information word in the FCV is initialized.
  370. .sp
  371. .in -4
  372. .ti +5
  373. The new coroutine is now ready to be started.  When the coroutine that created
  374. it is ready to have it begin, it can start it up via C_CALL or C_RESUME.
  375. .sp 3
  376. .he 'BDS C Coroutine Package''Transfer of Control'
  377. .ul 1
  378. 6. Transfer of control
  379. .sp
  380. .ti +5
  381. All of the three transfer-of-control mechanisms (C_CALL, C_RESUME, and
  382. C_DETACH) operate in a similar fashion.  All of them depend on the fact that
  383. a coroutine which is not in execution has its stack pointer saved in its FCV,
  384. and that the top two words on the stack are the BC register and PC at the
  385. time the coroutine last exited.  Most of the code is in a common assembly
  386. language procedure called CORPASS, which should
  387. .ul 1
  388. never
  389. be called directly by the user.
  390. The three types of control transfers work as follows:
  391. .sp
  392. .bo 1
  393. C_CALL:
  394. .sp
  395. .in +4
  396. .ti -2
  397. - Set the "caller" pointer in the destination coroutine's FCV to designate
  398. the originating coroutine.  Set the "type" word to indicate that the
  399. transfer type was CALL.
  400. .sp
  401. .ti -2
  402. - Enter the destination coroutine by calling "corpass".
  403. .sp
  404. .in -4
  405. .ti +0
  406. C_DETACH:
  407. .sp
  408. .in +4
  409. .ti -2
  410. - Determine the destination coroutine by retrieving the "caller" pointer from
  411. the originating coroutine's FCV.  Set the "type" word in the destination
  412. FCV to indicate that the transfer type was DETACH.
  413. .sp
  414. .ti -2
  415. - Enter the destination coroutine by calling "corpass".
  416. .sp
  417. .in -4
  418. .ti +0
  419. C_RESUME:
  420. .sp
  421. .in +4
  422. .ti -2
  423. - Retrieve the originating coroutine's "caller" pointer from its FCV, and
  424. store the "caller" pointer into the destination coroutine's FCV.
  425. .sp
  426. .ti -2
  427. - Set the "type" word in the destination FCV to indicate that the transfer
  428. type was RESUME.
  429. .sp
  430. .ti -2
  431. - Enter the destination routine by calling CORPASS.
  432. .sp
  433. .in -4
  434. .ti +5
  435. When CORPASS is called, the PC has already been placed on the top of the
  436. stack.  CORPASS is responsible for saving the rest of the context and
  437. getting to the destination coroutine.  It operates as follows:
  438. .sp
  439. .in +4
  440. .ti -2
  441. - The BC register is pushed on the stack, since the caller wants it to
  442. be preserved.
  443. .sp
  444. .ti -2
  445. - The stack pointer is saved in the originating coroutine's FCV.  The original
  446. context is now preserved.
  447. .sp
  448. .ti -2
  449. - The "passer" word in the target FCV is set to designate the originating FCV.
  450. .sp
  451. .ti -2
  452. - The "current FCV" pointer in memory is set to the target FCV, and the
  453. SP is reloaded from the FCV.  We are now executing within the target coroutine.
  454. .sp
  455. .ti -2
  456. - The BC register is popped off the stack, and a RET instruction is executed
  457. to resume execution in the target coroutine.  All of the target's context has
  458. been restored.
  459. .sp
  460. .in -4
  461. .ti +5
  462. It is an interesting exercise to verify that C_RESUME of the current coroutine
  463. does nothing, as indeed it ought.  Following the process will lead to a better 
  464. understanding of how the coroutine switching operates.
  465. .sp 3
  466. .he 'BDS C Coroutine Package''Initial Entry'
  467. .ul 1
  468. 7. Initial Entry into a Coroutine.
  469. .sp
  470. .ti +5
  471. As mentioned above, when a coroutine is initially created, its BC register
  472. (on the initial stack) is set to the initial entry address and its PC
  473. (also on the stack) is set to a procedure called "corstart".  "Corstart"
  474. is a driver program that is responsible for getting the coroutine started.
  475. All that it does is rearrange the register contents, and perform an ordinary
  476. C call to the initial entry of the coroutine.  The initial entry may be
  477. viewed in much the same light as the "main" function in an ordinary C
  478. program.
  479. .sp 3
  480. .he 'BDS C Coroutine Package''Falling off the End'
  481. .ul 1
  482. 8. Falling off the End
  483. .sp
  484. .ti +5
  485. The question now arises, "What happens when the main procedure of a coroutine
  486. executes a C 'return' statement?"  This unusual action is generally called 
  487. "falling off the end" of the coroutine.
  488. .sp
  489. .ti +5
  490. When a coroutine "falls off the end", it enters the "corstart" procedure again.
  491. The "corstart" procedure fixes up the stack, and then calls "detach."  This
  492. call has the effect of resuming whoever it was that called the coroutine that
  493. "fell off the end," and leaving the coroutine that "fell off" in a quiescent
  494. state.
  495. .sp
  496. .ti +5
  497. If some other coroutine then transfers control to the one that "fell off",
  498. CORSTART is resumed yet again. When this happens, it goes back up to the
  499. beginning and restarts the coroutine from its initial entry point.  
  500. The meaning of this becomes clear if one thinks of the coroutine as a
  501. program within a multi-tasking operating system.  When it is started initially,
  502. it enters at its main entry point, and performs whatever duties it has to do.
  503. It may require the services of other tasks; if so, it calls them, and
  504. they eventually return to it.  When it has completed its job, it returns to
  505. the operating system.  If anyone calls it thereafter, it has a new task
  506. to perform, and starts over again from the beginning.
  507. .sp 3
  508. .he 'BDS C Coroutine Package''Data Passing'
  509. .ul 1
  510. 9. Passing Data Between Coroutines
  511. .sp
  512. .ti +5
  513. In some of the discussion above, the notion that one coroutine passes some
  514. data item to another has been mentioned.  Given the structure presented so
  515. far, the way that this works is fairly simple.  The first coroutine, when
  516. it performs a CALL, DETACH, or RESUME, supplies an argument (the first argument
  517. to DETACH or the second to CALL or RESUME) which is the datum to pass.
  518. .sp
  519. .ti +5
  520. When a coroutine is re-entered, the value which the passer supplied is
  521. available as the return value of the CALL, DETACH, or RESUME which
  522. caused it to exit.  For instance, assume that there is a coroutine called
  523. "mailman", which accepts a message and returns a reply.  A request to the
  524. mailman might look something like:
  525. .sp
  526. .ti +10
  527. .bo 1
  528. reply = c_call (mailman, &message);
  529. .sp
  530. while the code in the "mailman" coroutine would look like:
  531. .sp
  532. .ti +10
  533. .bo 1
  534. next_message = c_detach (&reply);
  535. .sp
  536. .ti +5
  537. Upon the first entry to a coroutine (or re-entry if it has "fallen off the
  538. end"), the parameter given to CALL, DETACH, or RESUME is available as the
  539. argument of the initial entry procedure.  The main procedure of the "mailman"
  540. coroutine probably begins something like:
  541. .sp
  542. .ti +10
  543. .bo 1
  544. mailmaid (first_msg)
  545. .br
  546. .ti +14
  547. .bo 1
  548. struct msg * first_msg;
  549. .sp
  550. .ti +5
  551. Finally, if a coroutine "falls off the end", the value given to the "return"
  552. statement is the argument which is given to the implicit DETACH.  If the
  553. "mailman" coroutine is done with its rounds, it might say:
  554. .sp
  555. .ti +10
  556. .bo 1
  557. return (last_reply);
  558. .sp
  559. which would cause it to start all over the next time somebody gave it a
  560. message.
  561. .sp 3
  562. .he 'BDS C Coroutine Package''Main as a Coroutine'
  563. .ul 1
  564. 10. The Main Program as a Coroutine.
  565. .sp
  566. .ti +5
  567. Under the definitions of the above discussion, the main C program and its
  568. subroutines constitute a coroutine; they are a set of functions sharing a
  569. common stack (in this case, the main C stack).  In fact, the main program
  570. can be treated as a coroutine like any other:  one can CALL and RESUME it,
  571. adjust its FCV, and do all the other coroutine operations, with one exception:
  572. the effect of doing a DETACH from the main program.
  573. .sp
  574. .ti +5
  575. The problem if, of course, the philosophical question, "Who is the caller
  576. of the main program?"  The answer might be expected to be, "the operating
  577. system," and so the expected behaviour of a DETACH from the main program
  578. might be to resume executing whatever got us there.  In fact, however,
  579. there is no convenient way of saving the state of the coroutines when
  580. we return to CP/M, so this attitude, while consistent, isn't very useful.
  581. .sp
  582. .ti +5
  583. Instead, the coroutine package contains a dummy FCV that represents "the
  584. operating system."  If the main program inquires about its caller, it will
  585. receive this FCV in reply.  The difference is that any attempt to RESUME
  586. this procedure is treated as a disaster:  the package prints an error message
  587. on the console and quits.  Of course, if a return to the operating system
  588. is needed, it can still be done by returning from the main program or
  589. using the C procedure "exit()"; it is only DETACH and its allies that cause
  590. trouble.
  591. .sp
  592. .ti +5
  593. While this procedure is somewhat inconsistent, it is perhaps more useful in
  594. the long run to catch unexpected DETACHes from the main program or some
  595. coroutine which it has simply RESUMEd.
  596. .sp 3
  597. .he 'BDS C Coroutine Package''Further Reading'
  598. .ul 1
  599. 11. Further Reading.
  600. .sp
  601. .ti +5
  602. The file, "CORO.NRO," on the coroutine package disc contains the individual
  603. manual pages for the functions in the package.
  604. .sp
  605. .ti +5
  606. A more elaborate discussion of coroutines is found in:
  607. .sp
  608. Knuth, Donald E.
  609. .ul 1
  610. The Art of Computer Programming.
  611. Volume 1:
  612. .ul 1
  613. Fundamental Algorithms.
  614. 2nd ed., Reading, Massachusetts, Addison-Wesley, 1973.
  615. .sp
  616. Of particular interest are Sections 1.4.2, 1.4.4, and 2.2.5.
  617. e is treated as a disaster:  the package prints an error m